/*
 * Copyright 2002-2016 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework;

import org.aopalliance.intercept.Interceptor;

import org.springframework.aop.TargetSource;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;

/**
 * Factory for AOP proxies for programmatic use, rather than via declarative
 * setup in a bean factory. This class provides a simple way of obtaining
 * and configuring AOP proxy instances in custom user code.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @author Rob Harrop
 * @since 14.03.2003
 */

/**
 1. ProxyFactory 总结
	 工厂类 - 用于程序化创建AOP代理实例的工厂类，而非通过Bean工厂声明式配置
	 便捷工具 - 提供简单的方式来获取和配置自定义用户代码中的AOP代理实例
	 多构造方式 - 支持多种构造函数，可基于目标对象、接口列表、拦截器等不同方式创建代理工厂
 2. 内部成员方法说明
 构造方法:
	 ProxyFactory() - 创建新的代理工厂实例
	 ProxyFactory(Object target) - 基于目标对象创建代理工厂，自动代理目标实现的所有接口
	 ProxyFactory(Class<?>... proxyInterfaces) - 创建代理工厂，指定代理应实现的接口
	 ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) - 为指定接口和拦截器创建代理工厂
	 ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) - 为指定接口和目标源创建代理工厂
 核心方法:
	 getProxy() - 根据工厂设置创建新的代理对象，使用默认类加载器
	 getProxy(ClassLoader classLoader) - 根据工厂设置创建新的代理对象，使用指定类加载器
	 getProxy(Class<T> proxyInterface, Interceptor interceptor) - 静态方法，为接口和拦截器创建代理
	 getProxy(Class<T> proxyInterface, TargetSource targetSource) - 静态方法，为目标源创建代理
	 getProxy(TargetSource targetSource) - 静态方法，创建扩展目标类的代理

 3. 类关系结构
 ProxyCreatorSupport (abstract)
 └── ProxyFactory
 相关类关系说明:
	 ProxyCreatorSupport: ProxyFactory 的父类，提供了创建AOP代理的核心支持功能
	 AdvisedSupport: ProxyCreatorSupport 的父类，管理通知器(advisors)、通知链等AOP核心概念
	 ProxyConfig: AdvisedSupport 的父类，维护代理配置属性如proxyTargetClass等
	 ProxyFactory 是最顶层的具体实现类，专门用于程序化创建代理对象。




 4. 使用场景
 程序化代理创建 - 在不使用Spring容器的情况下手动创建AOP代理
 测试环境 - 在单元测试中快速创建代理对象进行测试
 动态代理需求 - 运行时根据条件动态创建不同类型的代理
 远程调用代理 - 如RMI等远程服务的代理创建
 自定义AOP框架 - 构建自定义AOP解决方案的基础组件


 5. 实际代码应用示例

 // 示例1: 基于目标对象创建代理
 MyService target = new MyServiceImpl();
 ProxyFactory factory = new ProxyFactory(target);
 factory.addAdvice(new MyMethodInterceptor());
 MyService proxy = (MyService) factory.getProxy();

 // 示例2: 基于接口和拦截器创建代理
 ProxyFactory factory2 = new ProxyFactory(MyService.class, new MyInterceptor());
 MyService proxy2 = factory2.getProxy();

 // 示例3: 使用静态方法创建代理
 MyService proxy3 = ProxyFactory.getProxy(MyService.class, new MyInterceptor());

 // 示例4: 基于TargetSource创建代理
 TargetSource targetSource = new SingletonTargetSource(new MyServiceImpl());
 MyService proxy4 = ProxyFactory.getProxy(MyService.class, targetSource);



 */
@SuppressWarnings("serial")
public class ProxyFactory extends ProxyCreatorSupport {

	/**
	 * Create a new ProxyFactory.
	 */
	public ProxyFactory() {
	}

	/**
	 * Create a new ProxyFactory.
	 * <p>Will proxy all interfaces that the given target implements.
	 * @param target the target object to be proxied
	 */
	public ProxyFactory(Object target) {
		// 设置被代理对象
		setTarget(target);
		// 设置被代理对象所实现的所有接口
		setInterfaces(ClassUtils.getAllInterfaces(target));
	}

	/**
	 * Create a new ProxyFactory.
	 * <p>No target, only interfaces. Must add interceptors.
	 * @param proxyInterfaces the interfaces that the proxy should implement
	 */
	public ProxyFactory(Class<?>... proxyInterfaces) {
		setInterfaces(proxyInterfaces);
	}

	/**
	 * Create a new ProxyFactory for the given interface and interceptor.
	 * <p>Convenience method for creating a proxy for a single interceptor,
	 * assuming that the interceptor handles all calls itself rather than
	 * delegating to a target, like in the case of remoting proxies.
	 * @param proxyInterface the interface that the proxy should implement
	 * @param interceptor the interceptor that the proxy should invoke
	 */
	public ProxyFactory(Class<?> proxyInterface, Interceptor interceptor) {
		addInterface(proxyInterface);
		addAdvice(interceptor);
	}

	/**
	 * Create a ProxyFactory for the specified {@code TargetSource},
	 * making the proxy implement the specified interface.
	 * @param proxyInterface the interface that the proxy should implement
	 * @param targetSource the TargetSource that the proxy should invoke
	 */
	public ProxyFactory(Class<?> proxyInterface, TargetSource targetSource) {
		addInterface(proxyInterface);
		setTargetSource(targetSource);
	}


	/**
	 * Create a new proxy according to the settings in this factory.
	 * <p>Can be called repeatedly. Effect will vary if we've added
	 * or removed interfaces. Can add and remove interceptors.
	 * <p>Uses a default class loader: Usually, the thread context class loader
	 * (if necessary for proxy creation).
	 * @return the proxy object
	 */
	public Object getProxy() {
		return createAopProxy().getProxy();
	}

	/**
	 * Create a new proxy according to the settings in this factory.
	 * <p>Can be called repeatedly. Effect will vary if we've added
	 * or removed interfaces. Can add and remove interceptors.
	 * <p>Uses the given class loader (if necessary for proxy creation).
	 * @param classLoader the class loader to create the proxy with
	 * (or {@code null} for the low-level proxy facility's default)
	 * @return the proxy object
	 */
	public Object getProxy(@Nullable ClassLoader classLoader) {
		return createAopProxy().getProxy(classLoader);
	}


	/**
	 * Create a new proxy for the given interface and interceptor.
	 * <p>Convenience method for creating a proxy for a single interceptor,
	 * assuming that the interceptor handles all calls itself rather than
	 * delegating to a target, like in the case of remoting proxies.
	 * @param proxyInterface the interface that the proxy should implement
	 * @param interceptor the interceptor that the proxy should invoke
	 * @return the proxy object
	 * @see #ProxyFactory(Class, org.aopalliance.intercept.Interceptor)
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getProxy(Class<T> proxyInterface, Interceptor interceptor) {
		return (T) new ProxyFactory(proxyInterface, interceptor).getProxy();
	}

	/**
	 * Create a proxy for the specified {@code TargetSource},
	 * implementing the specified interface.
	 * @param proxyInterface the interface that the proxy should implement
	 * @param targetSource the TargetSource that the proxy should invoke
	 * @return the proxy object
	 * @see #ProxyFactory(Class, org.springframework.aop.TargetSource)
	 */
	@SuppressWarnings("unchecked")
	public static <T> T getProxy(Class<T> proxyInterface, TargetSource targetSource) {
		return (T) new ProxyFactory(proxyInterface, targetSource).getProxy();
	}

	/**
	 * Create a proxy for the specified {@code TargetSource} that extends
	 * the target class of the {@code TargetSource}.
	 * @param targetSource the TargetSource that the proxy should invoke
	 * @return the proxy object
	 */
	public static Object getProxy(TargetSource targetSource) {
		if (targetSource.getTargetClass() == null) {
			throw new IllegalArgumentException("Cannot create class proxy for TargetSource with null target class");
		}
		ProxyFactory proxyFactory = new ProxyFactory();
		proxyFactory.setTargetSource(targetSource);
		proxyFactory.setProxyTargetClass(true);
		return proxyFactory.getProxy();
	}

}
